package spacewar2.objects;

import java.awt.Color;

import spacewar2.actions.SpacewarAction;
import spacewar2.powerups.SpacewarPowerupEnum;
import spacewar2.shadows.ShipShadow;
import spacewar2.utilities.Position;

/**
 * A spacewar ship is the main object in the simulator as it is the one the agents/clients control.
 * 
 * @author amy
 */
public class Ship extends SpacewarActionableObject {
    public static final int SHIP_RADIUS = 15;
    public static final int SHIP_MASS = 100;
    public static final int SHIP_INITIAL_ENERGY = 5000;
    public static final int RESPAWN_INCREMENT = 10;
    public static final int MAX_RESPAWN_INTERVAL = 500;
    public static final int MAX_ENERGY = 50000;
    /**
     * Maximum number of bullets simultaneously in the simulator.  This keeps ships 
     * from simply firing at every step 
     */
    public static final int MAX_BULLETS = 3;
    
	/**
	 * The name of the team this ship belongs to
	 */
	String teamName;
	
	/**
	 * The action the ship is currently executing
	 */
	SpacewarAction currentAction;
	
	/**
	 * Time checks left until the ship can respawn
	 */
	int respawnCounter;
	
	/**
	 * Number of beacons picked up by this ship
	 */
	int numBeacons;

	/**
	 * The amount of energy a ship has left
	 */
    double energy;
    
    /**
     * Last time the respawn counter was used
     */
    int lastRespawnCounter;

    /**
     * Current money a ship is holding (from the mined asteroids).  Note the 
     * money has to be turned into the base before it can be used by the team.
     */
    int money;
    
    /**
     * The color for this team
     */
    Color teamColor;
    
    /**
     * Number of bullets in the air (this is reset by the sim
     * when bullets explode or reach their target)
     */
    int numBulletsInAir;
    
	
	/**
	 * Make a new ship for the specified team.  
	 * @param teamName
	 */
	public Ship(String teamName, Color teamColor, Position location) {
		super(SHIP_MASS, SHIP_RADIUS, location);
		setDrawable(true);
		setAlive(true);
		this.teamName = teamName;
		shadow = new ShipShadow(this, teamColor);
		this.isControllable = true;
		this.isMoveable = true;
		respawnCounter = 0;
		numBeacons = 0;
		energy = SHIP_INITIAL_ENERGY;
		lastRespawnCounter = 0;
		money = 0;
		this.teamColor = teamColor;
		numBulletsInAir = 0;
	}
	
	/**
	 * Deep copy of a ship (used for security)
	 * @return
	 */
	public Ship deepClone() {
		Ship newShip = new Ship(teamName, teamColor, getPosition().deepCopy());
		
		newShip.setAlive(isAlive);
		newShip.money = money;
		newShip.lastRespawnCounter = lastRespawnCounter;
		newShip.numBeacons = numBeacons;
		newShip.energy = energy;
		newShip.respawnCounter = respawnCounter;
		newShip.shadow = new ShipShadow(newShip, teamColor);
		newShip.currentAction = currentAction;
		newShip.numBulletsInAir = numBulletsInAir;
		newShip.id = id;
		return newShip;
	}
	

	/**
	 * Return the amount of energy
	 * @return
	 */
	public double getEnergy() {
		return energy;
	}
	
	/**
	 * Update the energy of the ship.  If it falls below 0, mark the ship as dead
	 * 
	 * @param difference
	 */
	public void updateEnergy(double difference) {
		energy += difference;
		
		if (energy <= 0) {
			setAlive(false);
		}
		
		if (energy > MAX_ENERGY) {
			energy = MAX_ENERGY;
		}
	}

	/**
	 * Resets the ship energy to the initial level
	 */
	public void resetEnergy() {
		energy = SHIP_INITIAL_ENERGY;
	}
	
	/**
	 * Get the current amount of money
	 * @return
	 */
	public int getMoney() {
		return money;
	}
	
	/**
	 * Change the money amount by the specified difference
	 * @param difference
	 */
	public void updateMoney(int difference) {
		money += difference;
	}
	
	/**
	 * Sets the money to 0
	 */
	public void resetMoney() {
		money = 0;
	}
	
	
	/**
	 * Returns a new bullet if the ship is allowed to
	 * fire a new one.  Otherwise returns null.
	 * 
	 * @return
	 */
	public Bullet getNewBullet() {
		if (numBulletsInAir < MAX_BULLETS) {
			Position bulletPosition = getPosition().deepCopy();
			return new Bullet(bulletPosition, this);
		} else {
			return null;
		}
	}
	
	/**
	 * Increment the bullet count
	 * 
	 * @param bullet
	 */
	public void incrementBulletCount(){
		numBulletsInAir++;
	}
	
	public void decrementBulletCount() {
		numBulletsInAir--;
	}



	/**
	 * Ships need to behave slightly differently when set to dead or respawned 
	 * so this is an override of the abstract class
	 */
	public void setAlive(boolean value) {
		if (value == false) {
			respawnCounter = Math.min(lastRespawnCounter + RESPAWN_INCREMENT, MAX_RESPAWN_INTERVAL);
			lastRespawnCounter = respawnCounter; 
			resetMoney();
		} else {
			resetEnergy();
		}
		
		super.setAlive(value);
	}
	
	
	/**
	 * Return the number of beacons picked up by this ship
	 * @return
	 */
	public int getNumBeacons() {
		return numBeacons;
	}

	/**
	 * Increment the number of beacons for this ship
	 */
	public void incrementBeaconCount() {
		numBeacons++;
	}

	/**
	 * @return the teamName
	 */
	public String getTeamName() {
		return teamName;
	}

	/**
	 * @param teamName the teamName to set
	 */
	public void setTeamName(String teamName) {
		this.teamName = teamName;
	}

	/**
	 * Get the action the ship is currently executing
	 * @return
	 */
	public SpacewarAction getCurrentAction() {
		return currentAction;
	}

	/**
	 * Set the action the ship is currently executing
	 * Note, this should only be done within the simulator and not
	 * within the team client (where it will be ignored)
	 * 
	 * @param currentAction
	 */
	public void setCurrentAction(SpacewarAction currentAction) {
		this.currentAction = currentAction;
	}

	public String toString() {
		String str = "Ship id " + id + " team " + teamName;
		return str;
	}

	/**
	 * Ships have to wait a certain amount of time until they can respawn
	 */
	public boolean canRespawn() {
		respawnCounter--;
		
		if (respawnCounter <= 0) {
			return true;
		} else {
			return false;
		}
		
	}

	/**
	 * This is in place for when powerups are ready.
	 */
	protected void applyPowerup(SpacewarPowerupEnum powerup) {
		// NOTE THIS DOESN'T WORK YET
		// TODO: implement this
		
	}

}
